#pragma once
#include <queue>
#include "mypthread.hpp"
#include "Log.hpp"
#include "cond.hpp"
#include "mutex.hpp"

/* 单列模式实现 */
namespace ThreadPoolModule
{
    /* 展开命名空间 */
    using namespace MypthreadModule;
    using namespace LogModule;
    using namespace MutexModule;
    using namespace CondModule;

    static const int gnum = 5; /* 线程池线程默认数量 */

    template <typename T>
    class ThreadPool
    {
    private:
        void WalkAllBroadcast()
        {
            {
                /* 加锁保证原子性 */
                LockGuard lockguard(_mutex);
                /* 唤醒所有线程 */
                if (_sleeprnumber) /* 如果存在休眠线程就唤醒 */
                    _cond.Broadcast();
                LOG(LogLevel::DEBUG) << "唤醒所有的线程";
            }
        }

        void WalkOneSignal()
        {
            /* 此处不用加锁，入任务的过程是原子性的 */
            _cond.Signal();
            LOG(LogLevel::DEBUG) << "唤醒单个的线程";
        }

        /* 单列模式实现，私有化默认构造 */
        ThreadPool(int num = gnum) : _num(num), _isrunning(false), _sleeprnumber(0)
        {
            for (int i = 0; i < num; ++i)
            {
                _threads.emplace_back(
                    [this]
                    { HandlerTask(); });
            }
        }

        void Start()
        {
            /* 如果线程池已经启动了，不要重复启动 */
            if (_isrunning == true)
                return;

            /* 没有启动，设置成启动状态 */
            _isrunning = true;

            for (auto &thread : _threads)
            {
                LOG(LogLevel::INFO) << "thread start success! " << thread.Name();
                thread.Start();
            }
        }

        /* 禁用拷贝构造/赋值重载 */
        ThreadPool(const ThreadPool<T> &) = delete;
        ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;

    public:
        /* 外部调用获取对象，该函数必须是静态函数只属于类 */
        /* 防止多线程调用线程池，并发访问创建需要加锁 */
        static ThreadPool<T> *GetInstance()
        {
            /* 双层if循环用于防止多线程竞争锁而导致阻塞情况，一旦有一个线程成功创建，其他线程使用直接返回即可 */
            if (_inc == nullptr)
            {
                if (_inc == nullptr)
                {
                    LockGuard lockguard(_lock);
                    LOG(LogLevel::DEBUG) << "首次使用单例, 创建之....";
                    _inc = new ThreadPool<T>();
                    _inc->Start();
                }
            }
            return _inc;
        }

        bool Enqueue(const T &t)
        {
            /* 只有线程池开始启动才可以放入任务 */
            if (_isrunning == true)
            {
                /* 加锁保证原子性 */
                LockGuard lockguard(_mutex);
                _taskq.push(t);
                if (_threads.size() == _sleeprnumber) /* 当线程数量等于休眠数量时才去唤醒，不然让已经唤醒的线程取执行任务 */
                    WalkOneSignal();
                return true;
            }
            return false;
        }

        void Stop()
        {
            /* 如果线程池已经退出，不要重复退出 */
            if (_isrunning == false)
                return;

            /* 没有退出，设置为退出状态 */
            _isrunning = false;

            /* 唤醒所有等待的线程 */
            WalkAllBroadcast();
        }

        void Join()
        {
            /* 回收所有线程 */
            for (auto &thread : _threads)
            {
                thread.Join();
            }
        }

        /* 不传参设计 */
        void HandlerTask()
        {
            /* 获取名字 */
            char name[128];
            pthread_getname_np(pthread_self(), name, sizeof(name));
            while (true)
            {
                // 处理任务
                T t;
                /* 加锁保证原子性 */
                {
                    LockGuard lockguard(_mutex);
                    while (_taskq.empty() && _isrunning == true) /* 如果任务队列为空，线程池处理运行状态，等待 */
                    {
                        ++_sleeprnumber;
                        _cond.Wait(_mutex.GetMutex());
                        --_sleeprnumber;
                    }

                    /* 线程退出：1. 任务队列为空 2. _isruning == false状态 */
                    if (_taskq.empty() && _isrunning == false)
                    {
                        LOG(LogLevel::INFO) << name << " 退出了, 线程池退出 && 任务队列为空";
                        break;
                    }

                    /* 一定有任务 */
                    t = _taskq.front();
                    _taskq.pop();
                }
                // 处理任务不需要再临界区处理，线程一旦拿到任务就属于线程自己的了！
                t();
            }
        }

        ~ThreadPool()
        {
        }

    private:
        std::vector<Thread> _threads; /* 管理线程的数组 */
        int _num;                     /* 用于表示线程的个数 */
        std::queue<T> _taskq;         /* 任务队列 */
        Cond _cond;                   /* 条件变量 */
        Mutex _mutex;                 /* 互斥量 */
        bool _isrunning;              /* 用于表示线程池是否启动 */
        int _sleeprnumber;            /* 用于表示休眠的线程数量 */

        /* 静态变量只属于类 */
        static ThreadPool<T> *_inc; /* 线程池指针 */
        static Mutex _lock;         /* 静态锁，用于控制多线程访问并发创建 GetInstance() */
    };

    /* 初始化静态变量 */
    template <typename T>
    ThreadPool<T> *ThreadPool<T>::_inc = nullptr;

    template <typename T>
    Mutex ThreadPool<T>::_lock; /* 直接会去调用对应头文件的构造函数 */
}